package com.mikelouis.test.scala.proginscala.chapter28

/**
 * Created by yuazhu on 2/26/2015.
 */
object Tree3 {

  trait Tree[+T] {
    def elem: T

    def left: Tree[T]

    def right: Tree[T]
  }

  object EmptyTree extends Tree[Nothing] {
    def elem =
      throw new NoSuchElementException("EmptyTree.elem")

    def left =
      throw new NoSuchElementException("EmptyTree.left")

    def right =
      throw new NoSuchElementException("EmptyTree.right")
  }


  /**
   * use match to implement canEqual method
   */
  object Branch1 {

    class Branch[T](
                     val elem: T,
                     val left: Tree[T],
                     val right: Tree[T]
                     ) extends Tree[T] {

      // non capital t means means unknown type match
      override def equals(other: Any) = other match {
        case that: Branch[t] => this.elem == that.elem &&
          this.left == that.left &&
          this.right == that.right
        case _ => false
      }

      override def hashCode: Int =
        41 * (
          41 * (
            41 + elem.hashCode
            ) + left.hashCode
          ) + right.hashCode

      def canEqual(other: Any) = other match {
        case that: Branch[_] => true
        case _ => false
      }
    }

  }

  /**
   * use isInstanceOf to implement canEqual method
   */
  object Branch2 {

    class Branch[T](
                     val elem: T,
                     val left: Tree[T],
                     val right: Tree[T]
                     ) extends Tree[T] {

      override def equals(other: Any) = other match {
        case that: Branch[t] => this.elem == that.elem &&
          this.left == that.left &&
          this.right == that.right
        case _ => false
      }

      override def hashCode: Int =
        41 * (
          41 * (
            41 + elem.hashCode
            ) + left.hashCode
          ) + right.hashCode

      def canEqual(other: Any) = other.isInstanceOf[Branch[_]]
    }

  }

}
